/*
 * Created on 2004-01-06
 */
package org.opencube.oms;

import java.util.Date;

/**
 * @author <a href="mailto:maciek@fingo.pl">FINGO - Maciej Mroczko</a>
 * TODO: comment
 */
class Relation extends OMSNode
{
	/* The relation source element */
	private OMSElement sourceElement = null;
	/* The relation target element */
	private OMSElement targetElement = null;
	/* The complex attribute */ 
	private String complexAttribute = null;
	/* Composition flag */
	private boolean composition = false;
	/* The ordered flag should be set when the relation was 'inserted before' */
	private boolean ordered = false;
	/* Sibling order */
	private int siblingOrder = 0;
	/* Source element id */
	private String sourceElementId; 
	private String complexAttributeId;
	String getComplexAttributeId() {
		return complexAttributeId;
	}

	void setComplexAttributeId(String complexAttributeId) {
		this.complexAttributeId = complexAttributeId;
	}

	/**
	 * @param sourceElement
	 * @param targetElement
	 * @param complexAttribute
	 * @param composition
	 * @param id
	 * @param key
	 * @param beforeElement
	 * @param creater
	 * @param creatingDate
	 * @param modifier
	 * @param modifyingDate
	 */
	protected Relation( OMSElement sourceElement, String sourceElementId, OMSElement targetElement, String complexAttribute, String complexAttributeId, boolean composition, int siblingOrder, String id, String key, String creater, Date creatingDate, String modifier, Date modifyingDate )
	{
		super( id, key, creatingDate, creater, modifyingDate, modifier );
		
		this.sourceElement = sourceElement;
		this.sourceElementId = sourceElement.isNew() ? null : sourceElementId;
		this.targetElement = targetElement;
		this.complexAttribute = complexAttribute;
		this.composition = composition;
		this.siblingOrder = siblingOrder;
		
		this.complexAttributeId=complexAttributeId;
	}

	/**
	 * Returns the complex attribute
	 * 
	 * @return The complex attribute
	 */
	protected String getComplexAttribute()
	{
		return this.complexAttribute;
	}

	/**
	 * Returns the source element
	 * 
	 * @return Element - the source element
	 */
	protected OMSElement getSourceElement()
	{
		return this.sourceElement;
	}
	
	/**
	 * Returns target element
	 * 
	 * @return Element - the target element
	 */
	protected OMSElement getTargetElement()
	{
		return this.targetElement;
	}
	
	protected boolean isAssociation()
	{
		return !this.composition;
	}
	
	protected boolean isComposition()
	{
		return this.composition;
	}

	public String toString()
	{
		return "<relation id=\"" + getId() + "\" name=\"" + getName() + "\" state=\"" + getState() + "\" cat=\"" + getComplexAttribute() + "\" source_elm_id=\"" + getSourceElementId() + "\" target_elm_id=\"" + getTargetElement().getId() + "\"/>";  
	}
	
	protected boolean isOrdered()
	{
		return this.ordered;
	}
	protected void setOrdered( boolean ordered )
	{
		this.ordered = ordered;
	}
	
	protected Relation getNextRelation()
	{
		Relation[] relations = this.sourceElement.getRelationsByComplexAttribute( sourceElement.isRoot() ? OMSStructure.OBJECTS_ATTRIBUTE : this.complexAttribute );
		boolean found = false;
		if (relations==null) { 
			return null;
		}
		for (int i = 0; i < relations.length; i++)
		{
			if( this == relations[ i ] && i != relations.length - 1 )
			{
				found = true;
				continue;
			}
			if( found && isSiblingRelation( relations[ i ] ) )
			{
				return relations[ i ];
			}
		}
		return null;
	}
	
	private boolean isSiblingRelation( Relation relation )
	{
		return this != relation && relation.getSourceElementId().equals( getSourceElementId() ) && relation.getComplexAttribute().equals( getComplexAttribute() );
	}
	
	void setSourceElement( OMSElement element )
	{
		this.sourceElement = element;
		if( sourceElement != null && !sourceElement.isRoot() )
		{
			this.sourceElementId = sourceElement.getId();
		}
	}
	
	void setTargetElement( OMSElement element )
	{
		this.targetElement = element;
	}
	
	/**
	 * The deleting relation marks it as removed, moves it to the source element 
	 * structure relaion trash, and removes it from the source element relation list 
	 * as well as from the target element.
	 */
	public void delete() throws OMSStructureException
	{
		// marks a deleted
		super.delete();
		// remove from the source
		this.sourceElement.removeRelation( this );
		// moves to trash
		sourceElement.getOMSStructure().getRelationTrash().add( this );
	}
	
	protected int getSiblingOrder()
	{
		return this.siblingOrder;
	}
	
	protected String getSourceElementId()
	{
		return sourceElementId == null || isAssociation() ? getSourceElement().getId() : sourceElementId;
	}
	
}
